AFacility 계열 클래스 상속 문제
1. 문제

문제 1. 허브 기능을 하는 ACentralHub와 AExtensionHub의 상속 계층이 달라 허브의 기능을 통합할 수 없음
문제 2. AProductionFacility, AMiningFacility를 포함한 아이템을 입, 출력하는 시설과 같이 기능은 달라도, 동일한 로직을 가지는 클래스들이 있어 코드 중복이 일어남
2. 시도
방법 1. ACentralHub와 AExtensionHub를 AHub를 상속하도록 구조를 변경한다.
한계. 기존 AExtensionHub의 상위 계층의 로직을 다시 쓰는 것은 많은 코드 중복을 일으키며, 유지 보수에 어려움이 생김
방법 2. 공통되는 부모, 즉 AFacility에 중복되는 함수와 로직 구현
한계. 실제로 AFacility 기능이 아니기 때문에 적절하지 않음
2.1. 최종 결정
다음과 같은 원칙을 세워 클래스들을 구현한다.
- 허브와 같이 기능이 중복되지만 상속관계를 만들기 어려운 경우, 언리얼 인터페이스를 활용한다.
- 동일한 로직을 가지고 있지만 상속관계를 만들기 어려운 경우, 컴포넌트 또는 액터를 활용하여 로직을 구현 후 부착하는 방식을 사용한다.
- 위 문제가 중복되는 경우, 인터페이스, 컴포넌트, 액터를 적절하게 혼용해서 사용한다.
2.1.1. 코드
인터페이스 활용
CentralHub.h
class GSB_API ACentralHub :
public AFacility,
public IPowerProviderFacility,
public IHubFacility,
public IInputPortHandler,
public IOutputPortHandler,
public IPowerWireConnection
{
[...]
}
UItemStorageComponent* ACentralHub::GetHubStorageComponent()
{
return StorageComponent;
}
class GSB_API AExtensionHub : public APowerRelayFacility,
public IHubFacility,
public IInputPortHandler,
public IOutputPortHandler
{
[...]
}
UItemStorageComponent* AExtensionHub::GetHubStorageComponent()
{
if (UGSBFacilitySubsystem* FacilitySubsystem = GetGameInstance()->GetSubsystem<UGSBFacilitySubsystem>())
{
return FacilitySubsystem->GetCentralHub()->GetHubStorageComponent();
}
return nullptr;
}
인터페이스 + 컴포넌트 활용
ConveyorTriSplitter
class GSB_API AConveyorTriSplitter :
public AConstructibleFacility,
public IInputPortHandler,
public IOutputPortHandler,
public IChainDeconstrutableFacility
{
[...]
protected:
UPROPERTY(VisibleAnywhere)
URetryPrioritizedActorRequestHandlerComponent* InputPortHandler;
UPROPERTY(VisibleAnywhere)
URetryPrioritizedActorRequestHandlerComponent* OutputPortHandler;
[...]
}
인터페이스 + 컴포넌트 + 액터 활용
InputPort.h, OutputPort.h
class GSB_API AInputPort : public AItemPort, public IItemReceiver
class GSB_API AOutputPort : public AItemPort, public IItemSender
class GSB_API AProductionFacility :
public APowerDistributorLinkedFacility,
public IInputPortHandler,
public IOutputPortHandler
{
[...]
UPROPERTY(VisibleAnywhere)
URetryPrioritizedActorRequestHandlerComponent* InputPortHandler;
UPROPERTY(VisibleAnywhere)
URetryPrioritizedActorRequestHandlerComponent* OutputPortHandler;
[...]
}

3. 결과
- 기존 상속 구조를 유지하면서 유연한 설계가 가능한 형태의 시스템 구조
- 이후 UMG를 이용한 UI 개발에도 비슷한 설계로 적용이 가능했음(NamedSlot활용)